import { MODEL_NAME } from '../../constants/model-names';
import { STORY_ID, type StoryId } from '../../data/story';
import type { StoryItem, SuccessCondition } from '../../data/story/type';
import { EVENTS, type IEventBus } from '../../events';
import type { BaseSnapshot } from '../../systems/save';
import {
  STORY_STATE,
  type HistoryItem,
  type StoryState,
} from '../../systems/story/story-engine';
import { BaseModel } from '../base';

export interface StoryV1 extends BaseSnapshot {
  version: 1;
  completedStory: Record<StoryId, boolean>;
}

export type StorySnapshot = StoryV1;

export type StorySnapshotOld = StoryV1;

export class StoryModel extends BaseModel {
  public name = MODEL_NAME.STORY;
  private bus: IEventBus;
  private currentStoryKey: StoryId | null = null;
  private completedStory = new Map<StoryId, boolean>();
  private currentState: StoryState = STORY_STATE.IDLE;
  private currentItem: StoryItem | null = null;
  private visitedNodes: string[] = [];
  private achievedFlags: SuccessCondition[] = [];
  private history: HistoryItem[] = [];
  private hasAchievedAllSuccess = false;

  constructor(bus: IEventBus) {
    super();
    this.bus = bus;
    Object.values(STORY_ID).forEach((k) => this.completedStory.set(k, false));
  }

  public setStoryCompleted(key: StoryId) {
    this.completedStory.set(key, true);
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public isStoryCompleted(key: StoryId) {
    return this.completedStory.get(key) ?? false;
  }

  public setCurrentState(state: StoryState) {
    this.currentState = state;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public setCurrentItem(item: StoryItem | null) {
    this.currentItem = item;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public setVisitedNodes(nodes: string[]) {
    this.visitedNodes = nodes;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public setAchievedFlags(flags: SuccessCondition[]) {
    this.achievedFlags = flags;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public setHistory(history: HistoryItem[]) {
    this.history = history;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public setHasAchievedAllSuccess(hasAchievedAllSuccess: boolean) {
    this.hasAchievedAllSuccess = hasAchievedAllSuccess;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public setCurrentStoryKey(key: StoryId | null) {
    this.currentStoryKey = key;
    this.bus.emit(EVENTS.STORY_STATE_UPDATE);
  }

  public getCurrentStoryKey() {
    return this.currentStoryKey;
  }

  public get uiState() {
    const completedStory = {} as Record<StoryId, boolean>;
    this.completedStory.forEach((v, k) => (completedStory[k] = v));
    return {
      completedStory,
      currentState: this.currentState,
      currentItem: this.currentItem,
      visitedNodes: this.visitedNodes,
      achievedFlags: this.achievedFlags,
      history: this.history,
      hasAchievedAllSuccess: this.hasAchievedAllSuccess,
      currentStoryKey: this.getCurrentStoryKey(),
    };
  }

  public save(): StorySnapshot {
    const completedStory = {} as Record<StoryId, boolean>;
    this.completedStory.forEach((v, k) => (completedStory[k] = v));
    return {
      version: 1,
      completedStory,
    };
  }

  public load(snapshot: StorySnapshot) {
    this.completedStory = new Map();

    for (const key of Object.values(STORY_ID)) {
      this.completedStory.set(key, snapshot.completedStory[key] ?? false);
    }
  }
}
